<template>
  <div class="ai-panel-container">
    <!-- 可自由拖动的AI按钮 -->
    <div class="draggable-ai-button" ref="draggableButton" v-show="showDraggableButton" :style="{
      left: buttonPosition.left + 'px',
      top: buttonPosition.top + 'px'
    }" @mousedown="startDrag" @click.stop="handleClick">
      <div class="button-inner">
        <img v-if="customAvatar" :src="customAvatar" alt="AI Avatar" class="avatar-image">
        <i v-else class="fas fa-robot"></i>
      </div>
      <div class="pulse-effect"></div>
    </div>

    <!-- AI面板 -->
    <div class="ai-panel" :class="{ 'open': isPanelOpen }" :style="{ width: panelWidth + 'px' }">
      <!-- AI面板的头部 -->
      <div class="ai-header">
        <div class="ai-avatar" :style="avatarStyle">
          <img v-if="customAvatar" :src="customAvatar" alt="AI Avatar" class="avatar-image">
          <i v-else class="fas fa-robot"></i>
        </div>
        <div class="ai-info">
          <div class="ai-title">{{ title }}</div>
          <div class="ai-subtitle">
            <span class="status-indicator" :style="{ backgroundColor: statusColor }"></span>
            {{ subtitle }}
          </div>
        </div>
        <button class="close-button" @click="hidePanel">
          <i class="fas fa-times"></i>
        </button>
      </div>

      <!-- 聊天容器 -->
      <div class="chat-container" ref="chatContainer" @contextmenu.prevent="showContextMenu">
        <!-- 欢迎消息 -->
        <div class="welcome-message">
          <div class="welcome-content">
            <h3>{{ currentWelcomeTitle }}</h3>
            <p>{{ currentWelcomeMessage }}</p>
            <div class="quick-actions">
              <button v-for="(action, index) in currentQuickActions" :key="index" class="quick-action-btn"
                @click="handleQuickAction(action)">
                {{ action }}
              </button>
            </div>
          </div>
        </div>

        <!-- 消息列表 -->
        <div v-for="(message, index) in filteredMessages" :key="index" class="message"
          :class="[message.type, { 'streaming': message.streaming }]">
          <!-- AI消息头像 -->
          <div class="message-avatar" v-if="message.type === 'ai-message'">
            <img v-if="customAvatar" :src="customAvatar" alt="AI Avatar" class="avatar-image">
            <i v-else class="fas fa-robot"></i>
          </div>

          <!-- 用户消息头像 -->
          <div v-if="message.type === 'user-message'" class="message-avatar user-avatar">
            <i class="fas fa-user"></i>
          </div>

          <div class="message-content-wrapper">
            <!-- 思考动画部分 -->
            <div v-if="message.streaming && !message.content" class="typing-indicator">
              <div class="typing-dots">
                <div></div>
                <div></div>
                <div></div>
              </div>
              <span>AI 正在思考...</span>
            </div>

            <!-- 正常消息内容 -->
            <div class="message-content" v-if="message.content" v-html="message.content"></div>

            <!-- 消息操作按钮 (仅AI消息显示且非思考状态) -->
            <div class="message-actions" v-if="message.type === 'ai-message' && !message.streaming && message.content">
              <button class="action-btn" @click="copyMessage(message.content)" title="复制">
                <i class="far fa-copy"></i>
              </button>
              <button class="action-btn" @click="regenerateMessage(index)" title="重新生成">
                <i class="fas fa-sync-alt"></i>
              </button>
            </div>

            <div class="message-time" v-if="message.content || (message.streaming && !message.content)">
              <i class="far fa-clock"></i>
              {{ message.time }}
            </div>
          </div>
        </div>
      </div>

      <!-- 输入区域 -->
      <div class="input-area">
        <!-- 文件预览区域 -->
        <div class="file-tags-container" v-if="uploadedFiles.length > 0">
          <div class="file-tag" v-for="(file, index) in uploadedFiles" :key="index">
            <span class="tag-icon">
              <i v-if="isImageFile(file)" class="fas fa-image"></i>
              <i v-else-if="file.type.includes('pdf')" class="fas fa-file-pdf"></i>
              <i v-else-if="file.type.includes('doc')" class="fas fa-file-word"></i>
              <i v-else class="fas fa-file-alt"></i>
            </span>
            <span class="tag-name">{{ file.name }}</span>
            <button class="remove-tag" @click="removeFile(index)">
              <i class="fas fa-times"></i>
            </button>
          </div>
        </div>

        <!-- 输入框 -->
        <textarea ref="messageInput" v-model.trim="userInput" class="message-input" :placeholder="currentPlaceholder"
          @keypress.enter.exact.prevent="handleSendMessage" @keydown.enter.shift.exact="handleShiftEnter"
          rows="2"></textarea>
        
        <!-- 底部功能按钮区 -->
        <div class="input-actions">
          <!-- 左侧按钮组 -->
          <div class="left-actions">
            <!-- 文件上传按钮 -->
            <div class="action-btn file-upload-btn" @click="triggerFileUpload" v-if="activeTab !== 1" title="上传文件">
              <i class="fas fa-paperclip"></i>
              <input type="file" ref="fileInput" @change="handleFileUpload" style="display: none"
                accept="image/*,.pdf,.doc,.docx,.txt">
            </div>
            
            <!-- 导入paper按钮（仅在试卷对话中显示） -->
            <div class="action-btn import-paper-btn" @click="openImportDialog" v-if="activeTab === 1" title="导入试卷">
              <i class="fas fa-file-import"></i>
              <input type="file" ref="paperFileInput" style="display: none" accept=".paper" @change="handlePaperFileChange" />
            </div>
            
            <!-- 清空会话按钮 -->
            <div class="action-btn clear-session-btn" @click="clearSession" title="清空会话">
              <i class="fas fa-trash-alt"></i>
            </div>
          </div>
          
          <!-- 右侧按钮组 -->
          <div class="right-actions">
            <!-- AI指令助手按钮 -->
            <div class="ai-helper-container">
              <div class="action-btn ai-helper-btn" @click="openCommandsModal" ref="aiHelperBtn" title="AI指令助手">
                <i class="fas fa-lightbulb"></i>
              </div>
            </div>
            
            <!-- 语音按钮 -->
            <div class="voice-btn-container">
              <div class="action-btn voice-btn" 
                  @click="handleVoiceInput" 
                  :class="{'recording': isRecording}" title="语音输入">
                <i class="fas" :class="isRecording ? 'fa-stop' : 'fa-microphone'"></i>
                
                <!-- 录音波形动画 -->
                <div v-if="isRecording" class="voice-waves" :class="{'active': isUserSpeaking}">
                  <span :style="{ height: getWaveHeight(0) + 'px' }"></span>
                  <span :style="{ height: getWaveHeight(1) + 'px' }"></span>
                  <span :style="{ height: getWaveHeight(2) + 'px' }"></span>
                  <span :style="{ height: getWaveHeight(3) + 'px' }"></span>
                </div>
              </div>
              
              <!-- 智能化语音悬浮提示 -->
              <div class="voice-tooltip" v-if="isRecording || tempRecognitionResult">
                <span class="recording-time" v-if="isRecording">{{ formatRecordingTime(recordingDuration) }}</span>
                <span class="recognition-status" v-if="recognitionState" :class="{'listening': isUserSpeaking, 'processing': recognitionState === '处理中...', 'waiting': recognitionState === '等待说话' || recognitionState === '请开始说话'}">
                  {{ recognitionState }}
                  <i v-if="recognitionState === '处理中...'" class="fas fa-spinner fa-spin"></i>
                  <i v-else-if="isUserSpeaking" class="fas fa-volume-up pulse-icon"></i>
                  <i v-else-if="recognitionState === '等待说话' || recognitionState === '请开始说话'" class="fas fa-microphone-alt blink-icon"></i>
                </span>
                <div class="temp-result" v-if="tempRecognitionResult" ref="resultContainer">
                  "{{ tempRecognitionResult }}"
                </div>
                <div class="volume-indicator" v-if="isRecording && !tempRecognitionResult">
                  <div class="volume-bars">
                    <div v-for="i in 8" :key="i" class="volume-bar" 
                        :class="{ 'active': audioVolume > (i * 5) }"></div>
                  </div>
                </div>
                <div class="tooltip-actions" v-if="isRecording">
                  <button class="cancel-btn" @click.stop="stopSenseVoiceRecording">
                    结束
                  </button>
                </div>
              </div>
            </div>
            
            <!-- 发送按钮 -->
            <button class="send-button" @click="handleSendMessage" :disabled="!canSend">
              <i v-if="!isSending" class="fas fa-paper-plane"></i>
              <div v-else class="sending-spinner"></div>
            </button>
          </div>
        </div>
      </div>
    </div>

    <!-- 右键菜单 -->
    <div
      v-if="contextMenuVisible"
      class="ai-context-menu"
      :style="{ left: contextMenuX + 'px', top: contextMenuY + 'px' }"
      @click="handleContextMenuClick"
    >
      <div class="context-menu-item" @click="clearSession">清空会话</div>
    </div>

    <!-- Element风格的AI指令助手对话框 -->
    <el-dialog
      title="AI指令助手"
      :visible.sync="commandsVisible"
      width="400px"
      center
      @close="closeCommandsDialog">
      <div class="commands-container">
        <!-- 指令分类和命令 -->
        <div v-for="(category, index) in filteredCommandCategories" :key="index" class="command-category">
          <h4 class="category-title">{{ category.name }}</h4>
          <div class="command-list">
            <div 
              v-for="(command, cmdIndex) in category.commands" 
              :key="cmdIndex"
              class="command-item"
              @click="useCommand(command.text)">
              <div class="command-title">{{ command.text }}</div>
              <div class="command-desc">{{ command.description }}</div>
            </div>
          </div>
        </div>
      </div>
    </el-dialog>

    <!-- 添加导入paper的对话框 -->
    <el-dialog title="请填写导入后的试卷名称，请勿重复！" :visible.sync="importDialogVisible" :close-on-click-modal="false" width="30%">
      <el-input v-model="customPaperName" placeholder="试卷名称" />
      <span slot="footer" class="dialog-footer">
        <el-button @click="importDialogVisible = false">取消</el-button>
        <el-button type="primary" @click="handleImportDialogConfirm">确定</el-button>
      </span>
    </el-dialog>
  </div>
</template>

<script>
import { mapState, mapActions, mapGetters } from 'vuex'
// 导入axios用于发送文件请求
import axios from 'axios';

export default {
  name: 'AiPanel',
  props: {
    title: {
      type: String,
      default: 'AI助手'
    },
    subtitle: {
      type: String,
      default: '随时为您服务'
    },
    customAvatar: {
      type: String,
      default: ''
    },
    avatarBgColor: {
      type: String,
      default: 'linear-gradient(135deg, #6e8efb, #a777e3)'
    },
    statusColor: {
      type: String,
      default: '#4ade80'
    },
    collapsedWidth: {
      type: Number,
      default: 0
    },
    expandedWidth: {
      type: Number,
      default: 420
    }
  },
  data() {
    return {
      prompt: '',
      panelWidth: this.collapsedWidth,
      showDraggableButton: true,
      isDragging: false,
      dragStart: { x: 0, y: 0, time: 0 },
      buttonStartPos: { left: 0, top: 0 },
      windowWidth: window.innerWidth,
      windowHeight: window.innerHeight,
      showButton: null,
      welcomeMessageSent: false,
      welcomeMessageKey: 'ai_welcome_shown',
      contextMenuVisible: false,
      contextMenuX: 0,
      contextMenuY: 0,
      // AI指令助手相关
      showAiHelper: false,
      commandCategories: [
        {
          name: '题库指令',
          icon: 'fas fa-book',
          expanded: true,
          type: 'question', // 添加类型标识，用于筛选
          commands: [
            { 
              text: '创建题库', 
              description: '打开题库配置窗口' 
            },
            { 
              text: '保存题目', 
              description: '保存当前创建的题库和题目 （在创建题目或添加题目后输入）' 
            },
            { 
              text: '选择已有题库', 
              description: '打开选择题库窗口' 
            },
            { 
              text: '添加题目', 
              description: '打开题目配置窗口 （选择题库后使用）' 
            },
            { 
              text: '刷新页面', 
              description: '刷新当前主页数据' 
            },
            { 
              text: '跳转到试卷页面', 
              description: '跳转到试卷页面 ' 
            },
            { 
              text: '回到主页', 
              description: '回到当前的模块主页' 
            },
            { 
              text: '搜索包含语文的题库', 
              description: '显示名称包含语文的题库' 
            }
          ]
        },
        {
          name: '试卷指令',
          icon: 'fas fa-file-alt',
          expanded: true,
          type: 'paper', // 添加类型标识，用于筛选
          commands: [
            { 
              text: '创建一张2025语文基础卷上，时长120分钟', 
              description: '创建试卷' 
            },
            { 
              text: '选择2025语文基础卷上', 
              description: '选择到要操作的试卷' 
            },
            { 
              text: '修改试卷名称为2025语文基础卷下，时长100分钟', 
              description: '修改试卷的信息 （选择试卷后使用）' 
            },
            { 
              text: '删除试卷', 
              description: '删除当前的试卷 （选择试卷后使用）' 
            },
            { 
              text: '发布试卷（发布后不可撤回）', 
              description: '发布试卷为考试 （选择试卷后使用）' 
            },
            { 
              text: '导出试卷（Word、Excel、.paper）', 
              description: '导出试卷为相应的格式 （选择试卷后使用）' 
            },
            { 
              text: '查看试卷信息', 
              description: '打开当前试卷的预览页面 （选择试卷后使用' 
            },
            { 
              text: '搜索语文试卷', 
              description: '查询出题目名称包含语文的试卷' 
            },
            { 
              text: '导入试卷', 
              description: '导入别人的试卷试卷' 
            },
            { 
              text: '返回首页', 
              description: '回到当前模块主页' 
            },
            { 
              text: '跳转到题库页面', 
              description: '跳转到题库的页面' 
            },
            { 
              text: '刷新页面', 
              description: '刷新当前主页数据' 
            }
          ]
        }
        // 移除解析指令分类
      ],
      // 语音输入相关状态
      isRecording: false,
      recognition: null,
      tempRecognitionResult: '',
      recordingDuration: 0,
      recordingTimer: null,
      networkErrorCount: 0,
      lastSpeechTime: Date.now(), // 记录最后一次检测到语音的时间
      silenceTimer: null, // 静音计时器
      recognitionState: '等待说话', // 识别状态
      silenceThreshold: 1500, // 静音阈值，单位毫秒
      audioContext: null, // 音频上下文
      audioAnalyser: null, // 音频分析器
      audioDataArray: null, // 音频数据数组
      audioVolume: 0, // 当前音量
      isUserSpeaking: false, // 用户是否正在说话
      volumeCheckInterval: null, // 音量检查定时器
      // SenseVoice API相关
      mediaRecorder: null,
      audioChunks: [],
      audioBlob: null,
      senseVoiceToken: 'sk-ikdrxlnrfkpfmyfoppjscvzsjocitojslnfdrhpzwlemrdey', // 请在实际使用时替换为您的API令牌
      commandsDialogVisible: false,
      activeCommandTab: 'question',
      commandsVisible: false,
      importDialogVisible: false,
      customPaperName: '',
    }
  },
  computed: {
    ...mapState('aiPanel', [
      'isTyping',
      'isSending',
      'isPanelOpen',
      'activeTab',
      'buttonPosition',
      'uploadedFile',
      'uploadedFiles',
      'roleTabs',
      'userInput'
    ]),
    ...mapGetters('aiPanel', [
      'currentWelcomeMessage',
      'canSend',
      'currentRoleConfig',
      'messages'
    ]),

    currentWelcomeTitle() {
      return this.roleTabs[this.activeTab] && this.roleTabs[this.activeTab].welcomeTitle || this.title;
    },
    currentQuickActions() {
      return this.roleTabs[this.activeTab] && this.roleTabs[this.activeTab].quickActions || [];
    },
    currentPlaceholder() {
      return this.roleTabs[this.activeTab] && this.roleTabs[this.activeTab].placeholder || '输入问题或使用语音输入...';
    },
    isCurrentImageFile() {
      return this.uploadedFile && this.uploadedFile.type && this.uploadedFile.type.startsWith('image/');
    },
    avatarStyle() {
      return {
        background: this.avatarBgColor
      }
    },
    userInput: {
      get() {
        return this.$store.state.aiPanel.userInput;
      },
      set(value) {
        this.$store.commit('aiPanel/SET_USER_INPUT', value);
        this.prompt = value;
      }
    },
    filteredMessages() {
      return this.messages.filter(message => message.content || (message.streaming && !message.content));
    },
    // 根据当前activeTab筛选显示的指令分类
    filteredCommandCategories() {
      if (this.activeTab === 0) { // 题库标签
        return this.commandCategories.filter(category => category.type === 'question');
      } else if (this.activeTab === 1) { // 试卷标签
        return this.commandCategories.filter(category => category.type === 'paper');
      }
      // 对于其他标签或情况，返回所有指令分类
      return this.commandCategories;
    },
  },
  methods: {
    ...mapActions('aiPanel', [
      'sendMessage',
      'switchTab',
      'setUserInput',
      'setUploadedFile',
      'addUploadedFile',
      'removeUploadedFile',
      'closeConnection',
      'saveButtonPosition',
      'addWelcomeMessage',
      'initializeTabMessages',
      'initializeMessages'
    ]),

    formatDateTime(date) {
      const options = {
        year: 'numeric',
        month: '2-digit',
        day: '2-digit',
        hour: '2-digit',
        minute: '2-digit',
        second: '2-digit',
        hour12: false
      };
      return new Intl.DateTimeFormat('zh-CN', options).format(new Date(date));
    },

    async handleSendMessage() {
      if (!this.canSend) return;

      try {
        const currentInput = this.userInput.trim();
        const hasFiles = this.uploadedFiles.length > 0;

        this.scrollToBottom();

        // 构建匹配后端AiChatModelVO的参数
        const messageParams = {
          prompt: currentInput,
          agentType: this.currentRoleConfig.agentType || 'question',
          // 安全获取用户ID，或者回退到localStorage，或者使用默认空字符串
          userId: this.$store.state.user?.userInfo?.userId || localStorage.getItem('userId') || '',
          sessionId: localStorage.getItem('sessionId') || `session_${Date.now()}`, // 会话ID
          silent: false // 默认不静默
        };

        // 添加文件相关参数
        if (hasFiles) {
          // 按照后端VO要求，设置hasFile和file
          messageParams.hasFile = true;

          // 获取第一个文件的原始File对象（如果有）
          // 注意：后端VO只支持单个文件
          const firstFile = this.uploadedFiles[0];
          if (firstFile && firstFile.originalFile) {
            messageParams.file = firstFile.originalFile;
          }
        } else {
          messageParams.hasFile = false;
        }

        await this.$store.dispatch('aiPanel/sendMessage', messageParams);

      } catch (error) {
        console.error('发送消息失败:', error);
        this.$message.error(`发送失败: ${error.message}`);
      }
    },

    addWelcomeMessage() {
      this.$store.dispatch('aiPanel/addWelcomeMessage');
    },

    scrollToBottom() {
      if (!this.$refs.chatContainer) return;

      this.$nextTick(() => {
        const container = this.$refs.chatContainer;
        container.scrollTo({
          top: container.scrollHeight,
          behavior: 'smooth'
        });
      });
    },

    async handleSwitchTab(index) {
      try {
        const result = await this.switchTab(index);

        if (result?.route) {
          await this.$router.push(result.route).catch(err => {
            console.error('路由导航失败:', err);
          });
        }

        if (result?.defaultText) {
          this.setUserInput(result.defaultText);
        }

        if (!this.isPanelOpen) {
          this.showPanel();
        }

        this.$nextTick(() => {
          this.$refs.messageInput?.focus();
          this.scrollToBottom();
        });
      } catch (error) {
        console.error('切换标签失败:', error);
      }
    },

    handleQuickAction(action) {
      this.setUserInput(action);
      this.$nextTick(() => {
        this.$refs.messageInput?.focus();
      });
    },

    handleShiftEnter() {
      this.setUserInput(this.userInput + '\n');
      this.adjustTextareaHeight();
    },

    adjustTextareaHeight() {
      this.$nextTick(() => {
        const textarea = this.$refs.messageInput;
        if (textarea) {
          textarea.style.height = 'auto';
          textarea.style.height = `${Math.min(textarea.scrollHeight, 120)}px`;
        }
      });
    },

    triggerFileUpload() {
      this.$refs.fileInput?.click();
    },

    handleFileUpload(e) {
      const files = e.target.files;
      if (!files || files.length === 0) return;

      // 清空现有文件
      if (this.uploadedFiles.length > 0) {
        this.$store.commit('aiPanel/CLEAR_UPLOADED_FILES');
      }

      // 只取第一个文件
      const file = files[0];

      // 创建FormData对象用于文件上传
      const formData = new FormData();
      formData.append('file', file);

      // 创建文件数据对象，添加所需字段以匹配后端AiChatModelVO
      const fileData = {
        name: file.name,
        type: file.type,
        url: URL.createObjectURL(file),
        size: file.size,
        fileId: `file_${Date.now()}`, // 临时文件ID
        fileUrl: null, // 上传后的URL，初始为空
        originalFile: file // 保存原始文件对象以便后续上传
      };

      // 添加文件预览图的优化
      if (this.isImageFile(fileData)) {
        // 对于图片文件，可以直接使用URL.createObjectURL生成的URL
        this.$message.success({
          message: '图片已添加',
          duration: 1500
        });
      } else {
        // 对于非图片文件，显示文件类型的提示
        const fileTypeMap = {
          'pdf': 'PDF文档',
          'doc': 'Word文档',
          'docx': 'Word文档',
          'txt': '文本文件'
        };
        
        const fileExtension = file.name.split('.').pop().toLowerCase();
        const fileTypeName = fileTypeMap[fileExtension] || '文件';
        
        this.$message.success({
          message: `${fileTypeName}已添加`,
          duration: 1500
        });
      }

      this.addUploadedFile(fileData);
      this.scrollToBottom();
      e.target.value = '';
    },

    removeFile(index) {
      if (index === undefined) {
        this.setUploadedFile(null);
      } else {
        this.removeUploadedFile(index);
      }
    },

    copyMessage(text) {
      navigator.clipboard.writeText(text).then(() => {
        this.$emit('action', 'copy');
      }).catch(err => {
        console.error('复制失败:', err);
      });
    },

    regenerateMessage(index) {
      const lastUserMessageIndex = this.findLastUserMessageIndex();
      if (lastUserMessageIndex !== -1) {
        this.setUserInput(this.messages[lastUserMessageIndex].content);
        this.$nextTick(() => {
          this.handleSendMessage();
        });
      }
    },

    findLastUserMessageIndex() {
      for (let i = this.messages.length - 1; i >= 0; i--) {
        if (this.messages[i].type === 'user-message') {
          return i;
        }
      }
      return -1;
    },

    showPanel() {
      this.$store.commit('aiPanel/SET_PANEL_OPEN', true);
      this.panelWidth = this.expandedWidth;
      this.showDraggableButton = false;

      this.$nextTick(() => {
        this.$refs.messageInput?.focus();
        this.scrollToBottom();
      });
    },

    hidePanel() {
      this.$store.commit('aiPanel/SET_PANEL_OPEN', false);
      this.panelWidth = this.collapsedWidth;
      this.showDraggableButton = true;
    },

    startDrag(e) {
      this.isDragging = false;
      this.buttonStartPos = {
        left: this.buttonPosition.left,
        top: this.buttonPosition.top
      };
      this.dragStart = {
        x: e.clientX,
        y: e.clientY,
        time: Date.now()
      };
      document.addEventListener('mousemove', this.onDrag);
      document.addEventListener('mouseup', this.stopDrag);
    },

    onDrag(e) {
      const dx = e.clientX - this.dragStart.x;
      const dy = e.clientY - this.dragStart.y;

      if (Math.abs(dx) > 5 || Math.abs(dy) > 5) {
        this.isDragging = true;
      }

      // 计算新位置，确保按钮始终在视口内
      const buttonWidth = 60; // 按钮宽度
      const buttonHeight = 60; // 按钮高度
      const margin = 20; // 与视口边缘的最小距离

      const newLeft = Math.max(margin, Math.min(
        this.windowWidth - buttonWidth - margin,
        this.buttonStartPos.left + dx
      ));
      const newTop = Math.max(margin, Math.min(
        this.windowHeight - buttonHeight - margin,
        this.buttonStartPos.top + dy
      ));

      this.saveButtonPosition({
        left: newLeft,
        top: newTop
      });
    },

    stopDrag() {
      document.removeEventListener('mousemove', this.onDrag);
      document.removeEventListener('mouseup', this.stopDrag);

      if (this.isDragging) {
        this.saveButtonPosition(this.buttonPosition);
      }
      this.isDragging = false;
    },

    handleClick(e) {
      if (!this.isDragging && (Date.now() - this.dragStart.time < 200)) {
        this.showPanel();
      }
    },

    isImageFile(file) {
      return file?.type?.startsWith('image/');
    },

    clearAllFiles() {
      this.$store.commit('aiPanel/CLEAR_UPLOADED_FILES');
    },

    // 添加窗口大小变化处理
    handleResize() {
      this.windowWidth = window.innerWidth;
      this.windowHeight = window.innerHeight;

      // 如果按钮位置超出新的视口范围，调整位置
      const buttonWidth = 60;
      const buttonHeight = 60;
      const margin = 20;

      const newLeft = Math.max(margin, Math.min(
        this.windowWidth - buttonWidth - margin,
        this.buttonPosition.left
      ));
      const newTop = Math.max(margin, Math.min(
        this.windowHeight - buttonHeight - margin,
        this.buttonPosition.top
      ));

      if (newLeft !== this.buttonPosition.left || newTop !== this.buttonPosition.top) {
        this.saveButtonPosition({
          left: newLeft,
          top: newTop
        });
      }
    },

    shouldShowWelcomeMessage() {
      return !this.messages.some(msg => 
        msg.type === 'ai-message' && 
        msg.content === this.currentWelcomeMessage
      );
    },

    addWelcomeMessageOnce() {
      if (this.shouldShowWelcomeMessage() && !this.welcomeMessageSent) {
        this.addWelcomeMessage();
        this.welcomeMessageSent = true;
      }
    },

    clearWelcomeMessageState() {
      this.welcomeMessageSent = false;
    },

    /**
     * 处理页面卸载前的清理工作
     */
    handleBeforeUnload() {
      // 已无 sessionStorage 相关逻辑，留空或直接移除
    },

    showContextMenu(e) {
      this.contextMenuVisible = true;
      this.contextMenuX = e.clientX;
      this.contextMenuY = e.clientY;
      document.addEventListener('click', this.hideContextMenu);
    },

    hideContextMenu() {
      this.contextMenuVisible = false;
      document.removeEventListener('click', this.hideContextMenu);
    },

    clearSession() {
      // 使用Element UI的确认对话框
      this.$confirm('确定要清空当前会话吗?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        // 获取当前用户ID
        const userId = this.$store.state.user && this.$store.state.user.userInfo && this.$store.state.user.userInfo.userId;
        
        if (!userId) {
          console.warn('清空会话失败：用户ID不可用');
          return;
        }
        
        // 获取当前消息类型
        const currentAgentType = this.currentRoleConfig.agentType || 'question';
        
        // 清空当前类型的消息
        this.$store.commit('aiPanel/CLEAR_MESSAGES', {
          rootState: this.$store.state
        });
        
        // 不再手动添加欢迎消息，系统会自动添加
        
        this.hideContextMenu();
        
        // 显示成功提示
        this.$message.success({
          message: '已清空当前会话',
          duration: 2000
        });
      }).catch(() => {
        // 取消清空操作
        this.$message({
          type: 'info',
          message: '已取消清空操作'
        });      
      });
    },

    handleContextMenuClick(e) {
      e.stopPropagation();
    },

    handleVoiceInput() {
      // 检查语音识别环境
      const checkResult = this.checkSenseVoiceEnvironment();
      if (!checkResult.success) {
        this.$message.warning({
          message: checkResult.message,
          duration: 3000
        });
        return;
      }
      
      // 如果正在录音，则停止录音
      if (this.isRecording) {
        this.stopSenseVoiceRecording();
        return;
      }
      
      // 开始录音并显示智能提示
      this.$message.success({
        message: '开始语音识别，请说话...',
        duration: 2000
      });
      
      this.startSenseVoiceRecording();
    },
    
    // 检查SenseVoice环境
    checkSenseVoiceEnvironment() {
      // 检查网络连接
      if (!navigator.onLine) {
        return {
          success: false,
          message: '您当前处于离线状态，语音识别需要网络连接'
        };
      }
      
      // 检查MediaRecorder API支持
      if (!window.MediaRecorder) {
        return {
          success: false,
          message: '您的浏览器不支持语音录制功能'
        };
      }
      
      return {
        success: true
      };
    },
    
    // 开始使用SenseVoice API录音
    async startSenseVoiceRecording() {
      try {
        // 清理之前的状态
        this.audioChunks = [];
        this.audioBlob = null;
        
        // 状态初始化
        this.isRecording = true;
        this.tempRecognitionResult = '';
        this.recognitionState = '等待说话';
        this.startRecordingTimer();
        this.lastSpeechTime = Date.now(); // 初始化最后语音时间
        
        // 获取麦克风权限
        const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
        
        // 创建MediaRecorder
        this.mediaRecorder = new MediaRecorder(stream);
        
        // 收集音频数据
        this.mediaRecorder.ondataavailable = (event) => {
          if (event.data.size > 0) {
            this.audioChunks.push(event.data);
          }
        };
        
        // 录音开始事件
        this.mediaRecorder.onstart = () => {
          console.log('开始录制音频');
          this.recognitionState = '请开始说话';
        };
        
        // 录音停止事件
        this.mediaRecorder.onstop = () => {
          console.log('停止录制音频');
          this.recognitionState = '处理中...';
          
          // 创建音频Blob
          this.audioBlob = new Blob(this.audioChunks, { type: 'audio/wav' });
          
          // 发送到SenseVoice API
          this.sendToSenseVoiceAPI(this.audioBlob);
          
          // 关闭麦克风
          stream.getTracks().forEach(track => track.stop());
          
          // 清理音频分析相关资源
          this.cleanupAudioAnalysis();
        };
        
        // 开始录制
        this.mediaRecorder.start();
        
        // 设置最大录音时长 - 15秒后自动停止
        setTimeout(() => {
          if (this.isRecording && this.mediaRecorder && this.mediaRecorder.state === 'recording') {
            this.stopSenseVoiceRecording();
            this.$message.info({
              message: '已达到最大录音时长',
              duration: 2000
            });
          }
        }, 15000);
        
        // 初始化音频分析
        this.initAudioAnalysis(stream);
        
      } catch (error) {
        console.error('启动录音失败:', error);
        this.isRecording = false;
        this.recognitionState = '';
        
        if (error.name === 'NotAllowedError' || error.name === 'PermissionDeniedError') {
          this.$message.error({
            message: '请允许麦克风访问权限',
            duration: 3000
          });
        } else {
          this.$message.error({
            message: '启动语音识别失败: ' + error.message,
            duration: 3000
          });
        }
      }
    },
    
    // 停止SenseVoice录音
    stopSenseVoiceRecording() {
      try {
        if (this.mediaRecorder && this.mediaRecorder.state === 'recording') {
          this.mediaRecorder.stop();
        }
        
        this.isRecording = false;
        this.stopRecordingTimer();
        this.clearSilenceTimer();
        this.cleanupAudioAnalysis();
        
        // 不要在这里清除临时识别结果，让它在API响应后处理
        // this.tempRecognitionResult = '';
      } catch (error) {
        console.error('停止录音失败:', error);
        this.$message.error({
          message: '停止录音失败',
          duration: 2000
        });
      }
    },
    
    startRecordingTimer() {
      this.recordingDuration = 0;
      this.stopRecordingTimer();
      
      this.recordingTimer = setInterval(() => {
        this.recordingDuration += 1000;
      }, 1000);
    },
    
    stopRecordingTimer() {
      if (this.recordingTimer) {
        clearInterval(this.recordingTimer);
        this.recordingTimer = null;
      }
    },
    
    // 发送到SenseVoice API
    sendToSenseVoiceAPI(audioBlob) {
      // 创建FormData对象
      const form = new FormData();
      form.append("model", "FunAudioLLM/SenseVoiceSmall");
      form.append("file", audioBlob, "recording.wav");
      
      // API配置
      const options = {
        method: 'POST',
        headers: {
          Authorization: 'Bearer ' + this.senseVoiceToken,
        }
      };
      
      options.body = form;
      
      // 显示加载状态
      this.recognitionState = '识别中...';
      
      // 设置识别超时
      const recognitionTimeout = setTimeout(() => {
        if (this.recognitionState === '识别中...') {
          this.recognitionState = '识别时间较长，请稍候...';
        }
      }, 3000);
      
      // 发送请求
      fetch('https://api.siliconflow.cn/v1/audio/transcriptions', options)
        .then(response => {
          if (!response.ok) {
            throw new Error('API响应错误: ' + response.status);
          }
          return response.json();
        })
        .then(result => {
          console.log('识别结果:', result);
          clearTimeout(recognitionTimeout);
          
          // 处理成功响应
          if (result && result.text) {
            // 更新临时结果
            this.tempRecognitionResult = result.text;
            this.recognitionState = '识别成功';
            
            // 确保语音提示框在屏幕可见区域内
            this.$nextTick(() => {
              const voiceTooltip = document.querySelector('.voice-tooltip');
              if (voiceTooltip) {
                // 根据不同界面类型调整位置
                if (this.activeTab === 1) { // 试卷界面
                  voiceTooltip.style.bottom = '120px';
                } else { // 题库界面或其他
                  voiceTooltip.style.bottom = '80px';
                }
              }
            });
            
            // 短暂显示结果
            setTimeout(() => {
              // 处理并更新输入框
              const processedText = this.processRecognitionResult(result.text);
              const currentInput = this.userInput.trim();
              const newInput = currentInput ? `${currentInput} ${processedText}` : processedText;
              this.setUserInput(newInput);
              
              // 成功提示
              this.$message.success({
                message: '语音识别成功',
                duration: 1500
              });
              
              // 自动聚焦输入框
              this.$nextTick(() => {
                this.$refs.messageInput?.focus();
                
                // 清理状态
                this.recognitionState = '';
                this.tempRecognitionResult = '';
              });
            }, 1200); // 显示识别结果1.2秒
          } else {
            this.recognitionState = '未检测到有效语音';
            setTimeout(() => {
              this.recognitionState = '';
              this.tempRecognitionResult = '';
            }, 2000);
            // 不要抛出错误，静默处理
          }
        })
        .catch(error => {
          clearTimeout(recognitionTimeout);
          console.error('语音识别API错误:', error);
          
          this.recognitionState = '识别失败';
          setTimeout(() => {
            this.recognitionState = '';
          }, 1500);
          
          // 仅在开发环境显示详细错误
          if (process.env.NODE_ENV === 'development') {
            this.$message.error({
              message: '语音识别未成功完成',
              duration: 2000
            });
          }
        });
    },

    formatRecordingTime(duration) {
      const minutes = Math.floor(duration / 60000);
      const seconds = Math.floor((duration % 60000) / 1000);
      return `${minutes}:${seconds.toString().padStart(2, '0')}`;
    },

    // 智能处理语音识别结果
    processRecognitionResult(text) {
      if (!text) return '';
      
      // 去除多余空格
      let processed = text.trim().replace(/\s+/g, ' ');
      
      // 修复常见的语音识别问题
      processed = processed
        .replace(/。/g, '.')
        .replace(/，/g, ',')
        .replace(/？/g, '?')
        .replace(/！/g, '!')
        .replace(/：/g, ':');
      
      // 智能修正常见错误
      const corrections = {
        '谷歌': 'Google',
        '脸书': 'Facebook',
        '推特': 'Twitter',
        '微软': 'Microsoft',
        '苹果': 'Apple',
        '亚马逊': 'Amazon',
        'V U E': 'Vue',
        'view': 'Vue',
        'react的': 'React',
        'angular的': 'Angular'
      };
      
      // 应用修正
      Object.keys(corrections).forEach(key => {
        const regex = new RegExp(key, 'gi');
        processed = processed.replace(regex, corrections[key]);
      });
        
      return processed;
    },

    // 初始化音频分析
    initAudioAnalysis(stream) {
      try {
        // 创建音频上下文
        this.audioContext = new (window.AudioContext || window.webkitAudioContext)();
        
        // 创建音频源
        const source = this.audioContext.createMediaStreamSource(stream);
        
        // 创建分析器
        this.audioAnalyser = this.audioContext.createAnalyser();
        this.audioAnalyser.fftSize = 256;
        
        // 连接音频源和分析器
        source.connect(this.audioAnalyser);
        
        // 创建数据数组
        const bufferLength = this.audioAnalyser.frequencyBinCount;
        this.audioDataArray = new Uint8Array(bufferLength);
        
        // 开始定期检查音量
        this.startVolumeCheck();
      } catch (error) {
        console.error('初始化音频分析失败:', error);
      }
    },
    
    // 开始音量检查
    startVolumeCheck() {
      // 清除之前的计时器
      if (this.volumeCheckInterval) {
        clearInterval(this.volumeCheckInterval);
      }
      
      // 设置新的计时器，每100毫秒检查一次音量
      this.volumeCheckInterval = setInterval(() => {
        if (this.isRecording && this.audioAnalyser && this.audioDataArray) {
          // 获取音频数据
          this.audioAnalyser.getByteFrequencyData(this.audioDataArray);
          
          // 计算平均音量
          let sum = 0;
          for (let i = 0; i < this.audioDataArray.length; i++) {
            sum += this.audioDataArray[i];
          }
          this.audioVolume = sum / this.audioDataArray.length;
          
          // 判断是否有声音（音量阈值可以根据实际情况调整）
          const wasSpeaking = this.isUserSpeaking;
          this.isUserSpeaking = this.audioVolume > 15; // 音量阈值
          
          // 状态转换
          if (this.isUserSpeaking) {
            // 检测到声音，更新最后语音时间
            this.lastSpeechTime = Date.now();
            
            // 如果之前不是说话状态，更新状态
            if (!wasSpeaking) {
              this.recognitionState = '正在聆听...';
              this.clearSilenceTimer(); // 清除之前的静音计时器
            }
          } else if (wasSpeaking) {
            // 从说话状态变为不说话状态，开始计时
            this.startSilenceTimer();
          }
        }
      }, 100);
    },
    
    // 开始静音计时器
    startSilenceTimer() {
      // 清除之前的计时器
      this.clearSilenceTimer();
      
      // 设置新的静音计时器
      this.silenceTimer = setTimeout(() => {
        // 如果静音时间超过阈值且录音仍在进行，自动停止录音
        if (this.isRecording && Date.now() - this.lastSpeechTime >= this.silenceThreshold) {
          console.log('检测到静音，自动停止录音');
          this.recognitionState = '检测到停顿，正在处理...';
          this.stopSenseVoiceRecording();
        }
      }, this.silenceThreshold);
    },
    
    // 清除静音计时器
    clearSilenceTimer() {
      if (this.silenceTimer) {
        clearTimeout(this.silenceTimer);
        this.silenceTimer = null;
      }
    },
    
    // 清理音频分析相关资源
    cleanupAudioAnalysis() {
      // 清除音量检查计时器
      if (this.volumeCheckInterval) {
        clearInterval(this.volumeCheckInterval);
        this.volumeCheckInterval = null;
      }
      
      // 关闭音频上下文
      if (this.audioContext) {
        if (this.audioContext.state !== 'closed') {
          this.audioContext.close().catch(err => console.error('关闭音频上下文失败:', err));
        }
        this.audioContext = null;
      }
      
      // 清除其他相关变量
      this.audioAnalyser = null;
      this.audioDataArray = null;
      this.audioVolume = 0;
      this.isUserSpeaking = false;
    },

    // 添加在methods中
    getWaveHeight(index) {
      if (!this.isUserSpeaking) {
        // 静默状态下的默认高度
        return 5 + (index % 2) * 3;
      }
      
      // 根据音量计算高度，使波形更加生动
      const baseHeight = 5;
      const maxAdditionalHeight = 20;
      const volumeFactor = Math.min(1, this.audioVolume / 100);
      
      // 不同索引位置有不同的高度，创造波浪效果
      const offsets = [0, 0.7, 0.5, 0.8];
      const variation = offsets[index] || 0.5;
      
      return baseHeight + (maxAdditionalHeight * volumeFactor * variation);
    },

    formatFileSize(bytes) {
      if (bytes === 0) return '0 B';
      const k = 1024;
      const sizes = ['B', 'KB', 'MB', 'GB'];
      const i = Math.floor(Math.log(bytes) / Math.log(k));
      return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
    },

    // 添加methods
    toggleAiHelper() {
      // 切换菜单显示状态
      this.showAiHelper = !this.showAiHelper;
      
      // 生成上下文相关建议
      if (this.showAiHelper) {
        this.generateContextSuggestion();
        
        // 确保菜单在视口内显示
        this.$nextTick(() => {
          // 添加点击外部关闭菜单
          document.addEventListener('click', this.closeAiHelperOutside);
        });
      } else {
        document.removeEventListener('click', this.closeAiHelperOutside);
      }
    },
    
    closeAiHelperOutside(event) {
      if (this.$refs.aiHelperMenu && this.$refs.aiHelperBtn) {
        if (!this.$refs.aiHelperMenu.contains(event.target) && 
            !this.$refs.aiHelperBtn.contains(event.target)) {
          this.showAiHelper = false;
          document.removeEventListener('click', this.closeAiHelperOutside);
        }
      }
    },
    
    toggleCategory(index) {
      this.$set(this.commandCategories[index], 'expanded', !this.commandCategories[index].expanded);
    },
    
    useCommand(commandText) {
      // 替换命令中的占位符
      let finalCommand = commandText.replace(/\{([^}]+)\}/g, '________');
      
      // 设置到输入框
      this.setUserInput(finalCommand);
      
      // 关闭菜单
      this.showAiHelper = false;
      
      // 聚焦输入框
      this.$nextTick(() => {
        this.$refs.messageInput?.focus();
      });
    },
    
    useContextSuggestion() {
      this.setUserInput(this.contextBasedSuggestion);
      this.showAiHelper = false;
      
      this.$nextTick(() => {
        this.$refs.messageInput?.focus();
      });
    },
    
    generateContextSuggestion() {
      // 因为我们不再显示智能建议，这个方法可以保留但不做任何操作
      // 或者可以移除整个方法
    },
    forceUpdateMenu() {
      // 强制刷新菜单状态
      this.showAiHelper = false;
      
      // 短暂延迟后再重新显示
      setTimeout(() => {
        this.showAiHelper = true;
        
        // 确保菜单在正确位置
        this.$nextTick(() => {
          if (this.$refs.aiHelperMenu) {
            this.$refs.aiHelperMenu.style.zIndex = '9999';
            
            // 显示菜单状态提示
            this.$message.success({
              message: '已刷新AI指令助手菜单',
              duration: 1500
            });
          }
        });
      }, 100);
    },
    getCommandsByType(type) {
      return this.commandCategories.find(category => category.type === type)?.commands || [];
    },
    showCommandsModal() {
      this.commandsVisible = true;
    },
    openCommandsModal() {
      this.commandsVisible = true;
    },
    closeCommandsDialog() {
      this.commandsVisible = false;
    },
    // openImportDialog() {
    //   this.importDialogVisible = true;
    // },
    // handlePaperFileChange(e) {
    //   const file = e.target.files[0];
    //   // 处理导入的paper文件
    //   console.log('导入的paper文件:', file);
    // },
    // handleImportDialogConfirm() {
    //   // 处理导入对话框确认
    //   console.log('导入对话框确认:', this.customPaperName);
    //   this.importDialogVisible = false;
    // },
    // 打开导入paper对话框
    openImportDialog() {
      // this.customPaperName = '';
      this.importDialogVisible = true;
    },
    
    // 用户点击"确定"：先关闭弹窗，再触发文件选择
    handleImportDialogConfirm() {
      if (!this.customPaperName) {
        this.$message.warning("请填写导入后的试卷名称，请勿重复！");
        return;
      }
      
      
      
      // 弹出文件选择
      this.$refs.paperFileInput.click();
    },
    
    // 处理导入的paper文件
    async handlePaperFileChange(event) {
      const file = event.target.files[0];
      
      if (!file || !file.name.endsWith('.paper')) {
        this.$message.error("请上传 .paper 格式的文件！");
        return;
      }
      
      const formData = new FormData();
      formData.append("file", file);
      formData.append("paperName", this.customPaperName);
      
      try {
        // 显示上传中提示
        const loadingInstance = this.$loading({
          lock: true,
          text: '正在导入试卷...',
          spinner: 'el-icon-loading',
          background: 'rgba(0, 0, 0, 0.7)'
        });
        console.log("paperName:",this.customPaperName);
        
        const response = await axios.post(
          // "http://47.106.93.65:8080/user/paper/import-paper",
          "http://localhost:8080/user/paper/import-paper",
          formData,
          {
            headers: {
              Authorization: localStorage.getItem("token") || "",
              "Content-Type": "multipart/form-data"
            }
          }
        );
        
        const res = response.data;
        
        // 关闭加载提示
        loadingInstance.close();
        
        if (res.code === 200) {
          this.$message.success(res.message || "导入试卷成功！");
          this.importDialogVisible = false;



          // 通过websocket发送消息通知刷新试卷列表
          // 使用现有的websocket通信机制
          if (this.$websocket && typeof this.$websocket.sendMessage === 'function') {
            this.$websocket.sendMessage({ 
              messageType: 1, // 根据PaperIndex.vue中的messageType=1是刷新试卷列表
              content: "refresh_papers"
            });
          }
        } else {
          this.$message.error(res.message || "导入失败！");
        }
      } catch (error) {
        console.error("导入试卷失败:", error);
        this.$message.error("上传出错，请检查网络或服务器状态！");
      }
      
      // 清除 input 值，允许上传同一个文件多次
      event.target.value = '';
    },
  },
  watch: {
    userInput(newVal) {
      this.adjustTextareaHeight();
    },
    isPanelOpen(newVal) {
      if (newVal) {
        this.$nextTick(() => {
          this.scrollToBottom();
        });
      }
    },
    messages: {
      handler(newMessages) {
        this.scrollToBottom();
        if (newMessages.length === 0) {
          this.addWelcomeMessageOnce();
        }
      },
      deep: true
    },
    // 监听路由变化以更新AI面板
    '$route': {
      handler(to) {
        // 检测路由变化并更新面板

        // 精确的路由匹配逻辑
        let tabIndex = -1;
        
        // 试卷路由
        if (to.path.includes('/paper')) {
          tabIndex = 1; // 试卷(paper)索引
        }
        // 题库路由
        else if (to.path.includes('/question-bank')) {
          tabIndex = 0; // 题库(question)索引
        }
        // 其他路由使用默认逻辑
        else {
          // 原有的匹配逻辑
          tabIndex = this.roleTabs.findIndex(tab => to.path === tab.route);
          if (tabIndex === -1) {
            tabIndex = this.roleTabs.findIndex(tab => to.path.startsWith(tab.route));
          }
        }
        
        if (tabIndex !== -1 && tabIndex !== this.activeTab) {
          // 强制设置激活标签
          this.$store.commit('aiPanel/SET_ACTIVE_TAB', tabIndex);
          this.showButton = this.roleTabs[tabIndex];
          
          // 主动初始化对应标签的消息
          this.$store.dispatch('aiPanel/initializeTabMessages', tabIndex).then(() => {
            this.scrollToBottom();
          });
        }
      },
      immediate: true
    },
    // 监听用户信息的变化
    '$store.state.user.userInfo': {
      handler(newUserInfo) {
        if (newUserInfo && newUserInfo.userId) {
          // 用户信息已加载，手动初始化消息
          
          // 根据当前路径确定正确的标签
          const currentPath = this.$route.path;

          
          // 更精确的匹配: 优先完全匹配，然后才是前缀匹配
          let tabIndex = this.roleTabs.findIndex(tab => tab.route === currentPath);
          if (tabIndex === -1) {
            tabIndex = this.roleTabs.findIndex(tab => currentPath.startsWith(tab.route));
          }
          
       
          
          if (tabIndex !== -1) {
            // 强制设置正确的激活标签
            this.$store.commit('aiPanel/SET_ACTIVE_TAB', tabIndex);
            this.showButton = this.roleTabs[tabIndex];
          
            
            // 主动加载对应标签的消息
            this.$store.dispatch('aiPanel/initializeTabMessages', tabIndex).then(() => {
           
              this.scrollToBottom();
            });
          }
        }
      },
      immediate: true,
      deep: true
    }
  },
  mounted() {
    this.$store.dispatch('aiPanel/loadButtonPosition');
    
    // 初始化当前路由对应的标签
    const currentPath = this.$route.path;

    
    // 更精确的匹配: 优先完全匹配，然后才是前缀匹配
    let tabIndex = this.roleTabs.findIndex(tab => tab.route === currentPath);
        
    // 如果完全匹配失败，再尝试前缀匹配
    if (tabIndex === -1) {
      tabIndex = this.roleTabs.findIndex(tab => currentPath.startsWith(tab.route));
    }
    

    
    if (tabIndex !== -1) {
    
      // 设置当前标签
      this.$store.commit('aiPanel/SET_ACTIVE_TAB', tabIndex);
      this.showButton = this.roleTabs[tabIndex];
      
      // 只有当用户信息已加载时才初始化消息
      const userInfo = this.$store.state.user && this.$store.state.user.userInfo;
      if (userInfo && userInfo.userId) {
        this.initializeMessages();
      }
    }
    
    this.scrollToBottom();
    window.addEventListener('resize', this.handleResize);

    // 监听页面卸载事件，清除会话消息
    window.addEventListener('beforeunload', this.handleBeforeUnload);
  },
  beforeUnmount() {
    document.removeEventListener('mousemove', this.onDrag);
    document.removeEventListener('mouseup', this.stopDrag);
    window.removeEventListener('resize', this.handleResize);
    window.removeEventListener('beforeunload', this.handleBeforeUnload);
    
    // 清理语音识别资源
    // 停止Web Speech API识别
    if (this.recognition) {
      try {
        this.recognition.stop();
      } catch(e) {
        console.log('清理语音识别失败', e);
      }
      this.recognition = null;
    }
    
    // 停止录音
    if (this.mediaRecorder && this.mediaRecorder.state === 'recording') {
      try {
        this.mediaRecorder.stop();
      } catch(e) {
        console.log('清理录音失败', e);
      }
    }
    
    // 停止计时器
    this.stopRecordingTimer();
    this.clearSilenceTimer();
    this.cleanupAudioAnalysis();
    
    // 清除其他计时器
    if (this.volumeCheckInterval) {
      clearInterval(this.volumeCheckInterval);
    }
    
    this.closeConnection();
  }
}
</script>

<style lang="less" scoped>
/* 颜色变量定义 */
@primary: #6e8efb;
@primary-light: #e0e7ff;
@primary-dark: #5a7df4;
@secondary: #a777e3;
@success: #4ade80;
@info: #60a5fa;
@warning: #fbbf24;
@danger: #f87171;
@gray-100: #f3f4f6;
@gray-200: #e5e7eb;
@gray-300: #d1d5db;
@gray-400: #9ca3af;
@gray-500: #6b7280;
@gray-600: #4b5563;
@gray-700: #374151;
@gray-800: #1f2937;
@gray-900: #111827;
@panel-bg: #ffffff;
@panel-border: @gray-200;
@panel-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
@shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
@radius-lg: 12px;
@radius-md: 8px;
@radius-sm: 4px;

/* 动画定义 */
@keyframes fadeIn {
  from {
    opacity: 0;
    transform: translateY(10px);
  }

  to {
    opacity: 1;
    transform: translateY(0);
  }
}

@keyframes typingAnimation {

  0%,
  60%,
  100% {
    transform: translateY(0);
    opacity: 0.6;
  }

  30% {
    transform: translateY(-5px);
    opacity: 1;
  }
}

@keyframes typingCursor {
  0% {
    border-right-color: transparent;
  }

  50% {
    border-right-color: @primary;
  }

  100% {
    border-right-color: transparent;
  }
}

@keyframes spin {
  to {
    transform: rotate(360deg);
  }
}

@keyframes pulse {
  0% {
    transform: scale(1);
    opacity: 1;
  }

  50% {
    transform: scale(1.05);
    opacity: 0.7;
  }

  100% {
    transform: scale(1);
    opacity: 1;
  }
}

@keyframes blink-caret {

  from,
  to {
    opacity: 0
  }

  50% {
    opacity: 1
  }
}

@keyframes pulse-recording {
  0% {
    transform: scale(1);
    box-shadow: 0 0 0 0 rgba(110, 142, 251, 0.7);
  }
  70% {
    transform: scale(1.05);
    box-shadow: 0 0 0 10px rgba(110, 142, 251, 0);
  }
  100% {
    transform: scale(1);
    box-shadow: 0 0 0 0 rgba(110, 142, 251, 0);
  }
}

@keyframes wave-animation {
  0% {
    height: 5px;
    background: rgba(255, 255, 255, 0.5);
  }
  50% {
    height: 20px;
    background: rgba(255, 255, 255, 0.9);
  }
  100% {
    height: 5px;
    background: rgba(255, 255, 255, 0.5);
  }
}

@keyframes fade-in {
  from {
    opacity: 0;
    transform: translate(-50%, -10px);
  }
  to {
    opacity: 1;
    transform: translate(-50%, 0);
  }
}

@keyframes pulse-glow {
  0% {
    text-shadow: 0 0 5px rgba(255, 255, 255, 0.7);
  }
  50% {
    text-shadow: 0 0 15px rgba(255, 255, 255, 1), 0 0 20px rgba(255, 255, 255, 0.5);
  }
  100% {
    text-shadow: 0 0 5px rgba(255, 255, 255, 0.7);
  }
}

@keyframes fade-in-out {
  0%, 100% {
    opacity: 0.7;
  }
  50% {
    opacity: 1;
  }
}

/* 主容器样式 */
.ai-panel-container {
  position: relative;
  height: 100%;

  /* 可拖动AI按钮样式 */
  .draggable-ai-button {
    position: fixed;
    width: 60px;
    height: 60px;
    border-radius: 50%;
    background: linear-gradient(135deg, @primary, @secondary);
    color: white;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: grab;
    box-shadow: 0 4px 20px rgba(110, 142, 251, 0.3);
    transition: transform 0.2s, box-shadow 0.2s;
    user-select: none;
    z-index: 9999;

    &:hover {
      transform: scale(1.05);
      box-shadow: 0 6px 25px rgba(110, 142, 251, 0.4);

      .pulse-effect {
        opacity: 1;
        transform: scale(1.5);
      }
    }

    &:active {
      cursor: grabbing;
    }

    .button-inner {
      font-size: 1.8rem;
      position: relative;
      z-index: 2;
    }

    .pulse-effect {
      position: absolute;
      width: 100%;
      height: 100%;
      border-radius: 50%;
      background: rgba(255, 255, 255, 0.2);
      opacity: 0;
      transition: all 0.3s ease;
      z-index: 1;
    }
  }

  /* AI面板主样式 */
  .ai-panel {
    position: relative;
    display: none;
    flex-direction: column;
    background-color: @panel-bg;
    border: 1px solid @panel-border;
    box-shadow: @panel-shadow;
    height: 100%;
    margin-left: auto;
    overflow: hidden;

    &.open {
      display: flex;
    }

    /* 面板头部样式 */
    .ai-header {
      padding: 1rem 1.5rem;
      border-bottom: 1px solid @panel-border;
      display: flex;
      align-items: center;
      gap: 1rem;
      background: @panel-bg;

      .ai-avatar {
        width: 40px;
        height: 40px;
        border-radius: 50%;
        display: flex;
        align-items: center;
        justify-content: center;
        color: white;
        font-weight: 600;
        box-shadow: 0 4px 12px rgba(110, 142, 251, 0.25);
        flex-shrink: 0;
        position: relative;
        overflow: hidden;
        background: linear-gradient(135deg, #4F46E5, #7C3AED);
        border: 2px solid rgba(255, 255, 255, 0.2);
        transition: all 0.3s ease;
        
        &:hover {
          transform: scale(1.05);
          box-shadow: 0 6px 16px rgba(110, 142, 251, 0.35);
          border-color: rgba(255, 255, 255, 0.3);
        }
        
        .avatar-image {
          width: 100%;
          height: 100%;
          object-fit: cover;
        }
        
        i {
          font-size: 1.2rem;
          background: linear-gradient(135deg, #fff, #E0E7FF);
          -webkit-background-clip: text;
          background-clip: text;
          -webkit-text-fill-color: transparent;
          filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.1));
        }
      }

      .ai-info {
        flex: 1;
        min-width: 0;

        .ai-title {
          font-weight: 600;
          font-size: 1rem;
          color: @gray-900;
          margin-bottom: 0.25rem;
          white-space: nowrap;
          overflow: hidden;
          text-overflow: ellipsis;
        }

        .ai-subtitle {
          font-size: 0.75rem;
          color: @gray-500;
          display: flex;
          align-items: center;
          gap: 0.5rem;
          white-space: nowrap;
          overflow: hidden;
          text-overflow: ellipsis;

          .status-indicator {
            width: 8px;
            height: 8px;
            border-radius: 50%;
            display: inline-block;
            flex-shrink: 0;
          }
        }
      }

      .close-button {
        background: none;
        border: none;
        color: @gray-400;
        font-size: 1rem;
        cursor: pointer;
        transition: all 0.2s;
        padding: 0.5rem;
        border-radius: 50%;
        display: flex;
        align-items: center;
        justify-content: center;
        width: 36px;
        height: 36px;

        &:hover {
          color: @primary;
          background-color: @gray-100;
        }
      }
    }

    /* 全局文件标签区域样式 */
    .global-file-tags-container {
      padding: 1.25rem 1rem 0.5rem;
      border-bottom: none;
      background-color: transparent;
      margin-top: 0.25rem;

      .global-file-tags-scroll {
        display: flex;
        flex-wrap: wrap;
        gap: 0.75rem;
        width: 100%;
        justify-content: flex-start;
      }

      .global-file-tag {
        display: flex;
        align-items: center;
        gap: 0.5rem;
        background-color: @gray-100;
        border-radius: 16px;
        padding: 0.375rem 0.75rem;
        font-size: 0.85rem;
        color: @gray-700;
        border: 1px solid @panel-border;
        box-shadow: @shadow-sm;
        max-width: 240px;
        width: auto;
        position: relative;

        &:hover {
          background-color: @gray-100;
          border-color: @gray-300;

          .remove-tag-btn {
            opacity: 1;
          }
        }

        .file-icon {
          color: @primary;

          i {
            font-size: 1rem;
          }
        }

        .file-name {
          white-space: nowrap;
          overflow: hidden;
          text-overflow: ellipsis;
          max-width: 180px;
          font-weight: 500;
        }

        .remove-tag-btn {
          width: 18px;
          height: 18px;
          border-radius: 50%;
          background-color: @gray-300;
          color: @gray-700;
          border: none;
          display: flex;
          align-items: center;
          justify-content: center;
          cursor: pointer;
          padding: 0;
          font-size: 0.6rem;
          transition: all 0.2s;
          opacity: 0;
          /* 默认隐藏 */

          &:hover {
            background-color: @danger;
            color: white;
          }
        }
      }
    }

    /* 聊天容器样式 */
    .chat-container {
      flex: 1;
      padding: 1.5rem;
      overflow-y: auto;
      background-color: @gray-100;
      display: flex;
      flex-direction: column;
      gap: 1.25rem;

      &::-webkit-scrollbar {
        width: 6px;
      }

      &::-webkit-scrollbar-track {
        background: @gray-200;
        border-radius: 3px;
      }

      &::-webkit-scrollbar-thumb {
        background-color: @gray-400;
        border-radius: 3px;
      }

      /* 欢迎消息样式 */
      .welcome-message {
        background-color: @panel-bg;
        border-radius: @radius-lg;
        padding: 1.25rem;
        box-shadow: @shadow-sm;
        margin-bottom: 0.5rem;
        border: 1px solid @panel-border;

        .welcome-content {
          h3 {
            font-size: 1.1rem;
            color: @gray-900;
            margin-bottom: 0.75rem;
          }

          p {
            font-size: 0.9rem;
            color: @gray-600;
            line-height: 1.5;
            margin-bottom: 1.25rem;
          }

          .quick-actions {
            display: flex;
            flex-wrap: wrap;
            gap: 0.5rem;

            .quick-action-btn {
              background-color: @gray-100;
              color: @gray-800;
              border: none;
              border-radius: 20px;
              padding: 0.5rem 1rem;
              font-size: 0.8rem;
              cursor: pointer;
              transition: all 0.2s;
              white-space: nowrap;

              &:hover {
                background-color: @primary-light;
                color: @primary-dark;
              }
            }
          }
        }
      }

      /* 消息样式 */
      .message {
        display: flex;
        gap: 0.75rem;
        animation: fadeIn 0.3s ease-out;
        max-width: 85%;
        margin-bottom: 1rem;
        position: relative;

        /* 消息头像样式 */
        .message-avatar {
          width: 32px;
          height: 32px;
          border-radius: 50%;
          background: linear-gradient(135deg, #4F46E5, #7C3AED);
          display: flex;
          align-items: center;
          justify-content: center;
          flex-shrink: 0;
          color: white;
          font-size: 1rem;
          overflow: hidden;
          border: 2px solid rgba(255, 255, 255, 0.2);
          box-shadow: 0 4px 8px rgba(110, 142, 251, 0.2);
          transition: all 0.3s ease;
          
          &:hover {
            transform: scale(1.05);
            border-color: rgba(255, 255, 255, 0.3);
          }
          
          &.user-avatar {
            background: linear-gradient(135deg, @primary, @secondary);
          }
          
          .avatar-image {
            width: 100%;
            height: 100%;
            object-fit: cover;
          }
          
          i {
            background: linear-gradient(135deg, #fff, #E0E7FF);
            -webkit-background-clip: text;
            background-clip: text;
            -webkit-text-fill-color: transparent;
            filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.1));
          }
        }

        .message-content-wrapper {
          flex: 1;
          min-width: 0;

          /* 思考指示器样式 */
          .typing-indicator {
            display: flex;
            align-items: center;
            background-color: @panel-bg;
            border-radius: @radius-lg;
            padding: 0.75rem 1rem;
            box-shadow: @shadow-sm;
            margin-bottom: 0.5rem;
            border: 1px solid @panel-border;

            .typing-dots {
              display: flex;
              align-items: center;
              gap: 3px;
              margin-right: 10px;

              div {
                width: 8px;
                height: 8px;
                border-radius: 50%;
                background-color: @primary;
                animation: typingAnimation 1.5s infinite ease-in-out;

                &:nth-child(1) {
                  animation-delay: 0s;
                }

                &:nth-child(2) {
                  animation-delay: 0.2s;
                }

                &:nth-child(3) {
                  animation-delay: 0.4s;
                }
              }
            }

            span {
              font-size: 0.85rem;
              color: @gray-600;
            }
          }

          /* 消息内容样式 */
          .message-content {
            padding: 0.75rem 1rem;
            border-radius: @radius-md;
            font-size: 0.95rem;
            line-height: 1.5;
            box-shadow: @shadow-sm;
            position: relative;
            word-break: break-word;
            transition: all 0.3s ease;

            /* 打字机效果 */
            &.streaming::after {
              content: '|';
              animation: blink-caret 0.75s step-end infinite;
              color: @primary;
              position: absolute;
              right: 8px;
              bottom: 8px;
            }
          }

          /* 消息操作按钮样式 */
          .message-actions {
            display: flex;
            gap: 0.5rem;
            margin-top: 0.5rem;
            opacity: 1;

            .action-btn {
              background: rgba(255, 255, 255, 0.7);
              border: 1px solid @gray-200;
              color: @gray-600;
              font-size: 0.8rem;
              cursor: pointer;
              transition: all 0.2s;
              padding: 0.25rem 0.75rem;
              border-radius: 12px;
              display: flex;
              align-items: center;
              gap: 0.25rem;

              &:hover {
                color: @primary;
                background-color: white;
                border-color: @gray-300;
                box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
              }

              i {
                font-size: 0.7rem;
              }
            }
          }

          /* 消息时间样式 */
          .message-time {
            font-size: 0.7rem;
            color: @gray-500;
            margin-top: 0.5rem;
            display: flex;
            align-items: center;
            gap: 0.375rem;
            font-weight: 500;
          }
        }

        /* AI消息特殊样式 */
        &.ai-message {
          align-self: flex-start;

          .message-content {
            background-color: @panel-bg;
            color: @gray-800;
            border: 1px solid @panel-border;
            border-radius: 0 @radius-lg @radius-lg @radius-lg;
          }

          .message-time {
            justify-content: flex-start;
          }
        }

        /* 用户消息特殊样式 */
        &.user-message {
          align-self: flex-end;
          flex-direction: row-reverse;

          .message-content {
            background: linear-gradient(135deg, @primary, @secondary);
            color: white;
            border-radius: @radius-lg @radius-lg 0 @radius-lg;
          }

          .message-time {
            justify-content: flex-end;
          }
        }
      }

      /* 文件预览样式 */
      .file-preview {
        margin-top: 1rem;
        background-color: @panel-bg;
        border-radius: @radius-lg;
        padding: 1rem;
        border: 1px solid @panel-border;
        box-shadow: @shadow-sm;

        .file-preview-content {
          display: flex;
          align-items: center;
          position: relative;

          .preview-image {
            max-width: 200px;
            max-height: 200px;
            border-radius: @radius-md;
            object-fit: contain;
          }

          .file-info {
            display: flex;
            align-items: center;
            gap: 0.5rem;
            color: @gray-700;

            i {
              font-size: 1.5rem;
              color: @gray-500;
            }
          }

          .remove-file-btn {
            position: absolute;
            right: -8px;
            top: -8px;
            background-color: @danger;
            color: white;
            border: none;
            width: 24px;
            height: 24px;
            border-radius: 50%;
            display: flex;
            align-items: center;
            justify-content: center;
            cursor: pointer;
            font-size: 0.7rem;
            box-shadow: @shadow-sm;
          }
        }
      }
    }

    /* 输入区域样式 */
    .input-area {
      padding: 0.5rem 0.75rem 0.75rem;
      border: 1px solid #e5e7eb;
      border-radius: 16px;
      background-color: @panel-bg;
      display: flex;
      flex-direction: column;
      gap: 0.5rem;
      position: relative;
      min-height: auto;
      margin: 0.75rem;
      box-shadow: 0 1px 3px rgba(0, 0, 0, 0.02);

      /* 文件标签区域样式 */
      .file-tags-container {
        display: flex;
        flex-wrap: wrap;
        gap: 0.5rem;
        padding: 0.5rem 0 0.75rem;
        
        .file-tag {
          display: flex;
          align-items: center;
          background-color: #f3f4f6;
          border-radius: 4px;
          padding: 0.25rem 0.5rem;
          font-size: 0.8rem;
          color: #4b5563;
          max-width: 200px;
          border: 1px solid #e5e7eb;
          
          .tag-icon {
            margin-right: 0.35rem;
            color: #6366f1;
            display: flex;
            align-items: center;
          }
          
          .tag-name {
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
            max-width: 140px;
          }
          
          .remove-tag {
            background: none;
            border: none;
            color: #9ca3af;
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: center;
            padding: 0;
            margin-left: 0.35rem;
            width: 16px;
            height: 16px;
            border-radius: 50%;
            font-size: 0.7rem;
            
            &:hover {
              color: #ef4444;
              background-color: rgba(0, 0, 0, 0.05);
            }
          }
        }
      }

      /* 输入框样式 */
      .message-input {
        width: 100%;
        padding: 0.5rem 0;
        border: none;
        border-radius: 0;
        font-size: 0.9rem;
        outline: none;
        transition: all 0.3s;
        background-color: transparent;
        font-family: inherit;
        resize: none;
        min-height: 24px;
        max-height: none;
        overflow-y: visible;
        line-height: 1.5;
        word-wrap: break-word;
        color: #333;

        /* 移除滚动条相关样式 */
        &::-webkit-scrollbar {
          display: none;
        }

        &::placeholder {
          color: #9ca3af;
          opacity: 1;
          font-style: normal;
          font-size: 0.85rem;
          white-space: nowrap;
          overflow: hidden;
          text-overflow: ellipsis;
        }
      }

      /* 底部功能按钮区域 */
      .input-actions {
        display: flex;
        justify-content: space-between;
        align-items: center;
        padding-top: 0.375rem;
        border-top: 1px solid rgba(0, 0, 0, 0.05);
        
        /* 左侧按钮组 */
        .left-actions {
          display: flex;
          align-items: center;
          gap: 0.75rem;
        }
        
        /* 右侧按钮组 */
        .right-actions {
          display: flex;
          align-items: center;
          gap: 0.75rem;
        }
        
        /* 通用操作按钮样式 */
        .action-btn {
          width: 28px;
          height: 28px;
          border-radius: 50%;
          background-color: rgba(243, 244, 246, 0.8);
          color: #6b7280;
          display: flex;
          align-items: center;
          justify-content: center;
          cursor: pointer;
          transition: all 0.2s;
          flex-shrink: 0;

          i {
            font-size: 0.85rem;
          }

          &:hover {
            background-color: rgba(229, 231, 235, 0.9);
            color: #4f46e5;
            transform: translateY(-1px);
            box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
          }
        }

        /* 文件上传按钮 */
        .file-upload-btn {
          i {
            font-size: 1rem;
          }
        }
        
        /* 语音按钮相关样式 */
        .voice-btn-container {
          position: relative;
          
          .voice-btn {
            position: relative;
            overflow: hidden;
            
            i {
              font-size: 1rem;
              transition: transform 0.3s ease;
              position: relative;
              z-index: 2;
            }
            
            &:hover i {
              transform: scale(1.1);
            }
            
            &.recording {
              background: linear-gradient(135deg, @primary, darken(@secondary, 10%));
              color: white;
              box-shadow: 0 3px 10px rgba(110, 142, 251, 0.4);
              transform: scale(1.05);
              animation: pulse-recording 2s infinite;
              
              i {
                animation: fade-in-out 2s infinite;
              }
            }
          }
          
          .voice-tooltip {
            position: absolute;
            top: -120px;
            left: 50%;
            transform: translateX(-50%);
            background: linear-gradient(135deg, rgba(110, 142, 251, 0.95), rgba(167, 119, 227, 0.95));
            color: white;
            padding: 10px 12px;
            border-radius: 10px;
            font-size: 11px;
            white-space: nowrap;
            animation: fade-in 0.3s;
            z-index: 10000;
            box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
            min-width: 160px;
            max-width: 90vw;
            backdrop-filter: blur(5px);
            border: 1px solid rgba(255, 255, 255, 0.2);
            width: auto;
            
            &:after {
              content: '';
              position: absolute;
              bottom: -8px;
              left: 50%;
              transform: translateX(-50%);
              width: 0;
              height: 0;
              border-left: 8px solid transparent;
              border-right: 8px solid transparent;
              border-top: 8px solid rgba(110, 142, 251, 0.9);
            }
            
            .recording-time {
              font-size: 14px;
              font-weight: 600;
              display: block;
              text-align: center;
              margin-bottom: 5px;
              text-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
            }
            
            .recognition-status {
              font-size: 12px;
              opacity: 0.95;
              text-align: center;
              margin-bottom: 6px;
              animation: glow-pulse 1.5s infinite;
              display: block;
              font-weight: 500;
              
              &.listening {
                color: #4ade80;
                text-shadow: 0 0 10px rgba(74, 222, 128, 0.5);
              }
              
              &.processing {
                color: #60a5fa;
                text-shadow: 0 0 10px rgba(96, 165, 250, 0.5);
              }
              
              &.waiting {
                color: #fbbf24;
                text-shadow: 0 0 10px rgba(251, 191, 36, 0.5);
              }
              
              .pulse-icon {
                animation: pulse-glow 1.5s infinite;
              }
              
              .blink-icon {
                animation: blink-caret 1s infinite;
              }
            }
            
            .temp-result {
              font-size: 12px;
              min-width: 200px;
              max-width: 300px;
              white-space: normal;
              text-align: center;
              opacity: 0.95;
              overflow: visible;
              overflow-wrap: break-word;
              word-break: break-all;
              background: rgba(255, 255, 255, 0.15);
              padding: 10px 12px;
              border-radius: 6px;
              margin-top: 4px;
              margin-bottom: 4px;
              box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1) inset;
              border: 1px solid rgba(255, 255, 255, 0.1);
              position: relative;
              z-index: 10000;
            }
            
            .volume-indicator {
              margin: 8px auto 6px;
              width: 80%;
              
              .volume-bars {
                display: flex;
                justify-content: center;
                align-items: flex-end;
                height: 16px;
                gap: 2px;
                
                .volume-bar {
                  width: 3px;
                  height: 5px;
                  background: rgba(255, 255, 255, 0.3);
                  border-radius: 1px;
                  transition: all 0.1s ease;
                  
                  &.active {
                    background: rgba(255, 255, 255, 0.9);
                    box-shadow: 0 0 4px rgba(255, 255, 255, 0.7);
                  }
                  
                  &:nth-child(1) { height: 4px; }
                  &:nth-child(2) { height: 6px; }
                  &:nth-child(3) { height: 8px; }
                  &:nth-child(4) { height: 10px; }
                  &:nth-child(5) { height: 12px; }
                  &:nth-child(6) { height: 10px; }
                  &:nth-child(7) { height: 8px; }
                  &:nth-child(8) { height: 6px; }
                }
              }
            }
            
            .tooltip-actions {
              display: flex;
              justify-content: center;
              margin-top: 8px;
              
              .cancel-btn {
                background: rgba(255, 255, 255, 0.2);
                border: 1px solid rgba(255, 255, 255, 0.3);
                color: white;
                font-size: 11px;
                cursor: pointer;
                transition: all 0.2s;
                padding: 3px 10px;
                border-radius: 12px;
                
                &:hover {
                  background: rgba(255, 255, 255, 0.3);
                  transform: translateY(-1px);
                  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
                }
              }
            }
            
            /* 呼吸光效 */
            &:before {
              content: '';
              position: absolute;
              top: -3px;
              left: -3px;
              right: -3px;
              bottom: -3px;
              border-radius: 12px;
              background: linear-gradient(135deg, rgba(110, 142, 251, 0.3), rgba(167, 119, 227, 0.3));
              z-index: -1;
              animation: pulse-border 2s infinite;
              opacity: 0;
            }
            
            /* 仅在录音状态显示边框动画 */
            &:has(.recording-time) {
              &:before {
                opacity: 1;
              }
            }
          }
          
          .voice-waves {
            position: absolute;
            bottom: 0;
            left: 0;
            right: 0;
            height: 100%;
            display: flex;
            align-items: center;
            justify-content: center;
            padding: 6px;
            opacity: 0.6;
            transition: opacity 0.3s ease;
            
            &.active {
              opacity: 1;
            }
            
            span {
              display: inline-block;
              width: 2px;
              margin: 0 2px;
              background: rgba(255, 255, 255, 0.7);
              border-radius: 2px;
              transition: height 0.1s ease-out;
              
              &:nth-child(1) { animation-delay: 0s; }
              &:nth-child(2) { animation-delay: 0.2s; }
              &:nth-child(3) { animation-delay: 0.4s; }
              &:nth-child(4) { animation-delay: 0.6s; }
            }
          }
        }
      }
    }

    // 保留原有的AI助手菜单相关样式，但需要确保它在面板之外显示
    .ai-helper-menu {
      position: fixed !important; /* 固定定位，覆盖所有可能的样式 */
      top: 50% !important;
      left: 50% !important;
      transform: translate(-50%, -50%) !important; /* 居中 */
      width: 360px;
      background: white;
      border-radius: 12px;
      box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
      z-index: 10000 !important; /* 确保最高层级 */
      overflow: hidden;
      animation: menu-popup 0.3s cubic-bezier(0.16, 1, 0.3, 1);
      border: 1px solid #eaeaea;
      max-height: 80vh;
      overflow-y: auto;
    }
  }
}

@keyframes menu-popup {
  from {
    opacity: 0;
    transform: translate(-50%, -48%) scale(0.9);
  }
  to {
    opacity: 1;
    transform: translate(-50%, -50%) scale(1);
  }
}

/* 添加背景遮罩 */
.ai-helper-menu::before {
  content: '';
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(0, 0, 0, 0.3);
  backdrop-filter: blur(4px);
  z-index: -1;
  animation: fade-in 0.3s ease forwards;
}

@keyframes fade-in {
  from {
    opacity: 0;
    backdrop-filter: blur(0px);
  }
  to {
    opacity: 1;
    backdrop-filter: blur(4px);
  }
}

/* 修改角色标签栏样式，使按钮居右 */
.role-tabs-container {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

/* AI助手按钮 */
.ai-helper-btn {
  background-color: rgba(79, 70, 229, 0.1);
  color: #4F46E5;
  width: 28px;
  height: 28px;
  
  &:hover {
    background-color: rgba(79, 70, 229, 0.2);
    box-shadow: 0 2px 4px rgba(79, 70, 229, 0.2);
    color: #4338ca;
  }
  
  i {
    font-size: 0.85rem;
  }
}

/* 发送按钮样式 */
.send-button {
  width: 28px;
  height: 28px;
  background-color: #6366f1;
  color: white;
  border: none;
  border-radius: 50%;
  font-weight: 500;
  cursor: pointer;
  transition: all 0.2s;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: none;
  flex-shrink: 0;

  &:hover:not(:disabled) {
    transform: translateY(-1px);
    box-shadow: 0 2px 4px rgba(99, 102, 241, 0.4);
    background-color: #4f46e5;
  }

  &:active:not(:disabled) {
    transform: translateY(0);
  }

  &:disabled {
    opacity: 0.7;
    cursor: not-allowed;
    background-color: #d1d5db;
  }

  i {
    font-size: 0.8rem;
  }

  .sending-spinner {
    width: 0.8rem;
    height: 0.8rem;
    border: 2px solid rgba(255, 255, 255, 0.3);
    border-radius: 50%;
    border-top-color: white;
    animation: spin 1s linear infinite;
  }
}

/* 清空会话按钮 */
.clear-session-btn {
  color: #6b7280;
  
  &:hover {
    color: #ef4444;
    background-color: rgba(239, 68, 68, 0.1);
  }
  
  i {
    font-size: 0.8rem;
  }
}

.category {
  margin-bottom: 12px;
  border-radius: 0;
  overflow: hidden;
  border: none;
}

.category-header {
  padding: 10px 16px;
  background: #f9fafb;
  display: flex;
  align-items: center;
  
  i {
    margin-right: 10px;
    color: #4b5563;
  }
  
  span {
    flex: 1;
    font-weight: 500;
    font-size: 14px;
  }
}

.category-commands {
  padding: 8px;
}

.command-item {
  padding: 12px;
  background: white;
  transition: all 0.2s;
  cursor: pointer;
  border: 1px solid #f3f4f6;
  border-radius: 8px;
  margin-bottom: 8px;
  
  &:hover {
    background: #f9fafb;
    transform: translateY(-1px);
    box-shadow: 0 2px 5px rgba(0,0,0,0.03);
  }
  
  .command-text {
    font-weight: 500;
    margin-bottom: 5px;
    font-size: 14px;
  }
  
  .command-description {
    font-size: 12px;
    color: #6b7280;
  }
}

.menu-header {
  padding: 12px 16px;
  border-bottom: 1px solid #f3f4f6;
  display: flex;
  align-items: center;
  justify-content: space-between;
  
  h3 {
    margin: 0;
    font-size: 16px;
    font-weight: 500;
  }
  
  .close-menu {
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    
    i {
      font-size: 16px;
      color: #9ca3af;
    }
  }
}

.commands-dialog {
  .command-categories-wrapper {
    .commands-tabs {
      .command-list {
        .command-card {
          padding: 1rem;
          border-radius: 6px;
          margin-bottom: 0.5rem;
          background: white;
          transition: all 0.2s;
          cursor: pointer;
          border: 1px solid #f3f4f6;
          
          &:hover {
            background: #f3f4f6;
            transform: translateY(-1px);
            box-shadow: 0 2px 5px rgba(0,0,0,0.05);
          }
          
          .command-title {
            font-weight: 500;
            margin-bottom: 0.25rem;
          }
          
          .command-desc {
            font-size: 0.8rem;
            color: #6b7280;
          }
        }
      }
    }
  }
}

.commands-container {
  max-height: 60vh;
  overflow-y: auto;
  
  /* 美化滚动条 */
  &::-webkit-scrollbar {
    width: 6px;
  }
  
  &::-webkit-scrollbar-track {
    background: #f3f4f6;
    border-radius: 4px;
  }
  
  &::-webkit-scrollbar-thumb {
    background-color: #d1d5db;
    border-radius: 4px;
    transition: all 0.3s ease;
  }
  
  &::-webkit-scrollbar-thumb:hover {
    background-color: #9ca3af;
  }
  
  .command-category {
    margin-bottom: 16px;
    
    .category-title {
      font-size: 16px;
      margin-bottom: 12px;
      font-weight: 500;
      color: #333;
      padding-bottom: 8px;
      border-bottom: 1px solid #f0f0f0;
    }
    
    .command-list {
      display: flex;
      flex-direction: column;
      gap: 8px;
      
      .command-item {
        padding: 12px;
        border: 1px solid #eaeaea;
        border-radius: 4px;
        cursor: pointer;
        transition: all 0.2s;
        
        &:hover {
          background: #f9fafb;
          border-color: #d1d5db;
        }
        
        .command-title {
          font-size: 14px;
          font-weight: 500;
          margin-bottom: 4px;
          color: #333;
        }
        
        .command-desc {
          font-size: 12px;
          color: #666;
        }
      }
    }
  }
}

/* 导入paper按钮样式 */
.import-paper-btn {
  background-color: rgba(79, 70, 229, 0.1);
  color: #4F46E5;
  
  &:hover {
    background-color: rgba(79, 70, 229, 0.2);
    color: #4338ca;
  }
  
  i {
    font-size: 0.85rem;
  }
}
</style>

